using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace DA.AnimGraph {
    public class BinaryDataBufferWriter : IDisposable {
        private readonly MemoryStream _stream;
        private readonly BinaryWriter _writer;

        public BinaryDataBufferWriter() {
            _stream = new MemoryStream();
            _writer = new BinaryWriter(_stream, Encoding.UTF8);
        }

        public void Dispose() {
            _writer?.Dispose();
            _stream?.Dispose();
        }

        public byte[] GetBuffer() {
            return _stream.ToArray(); // Return the complete binary data
        }

        public void WriteAGP(AnimGraphPublishAsset agp) {
            _writer.Write((ulong)agp.fileUuid); // 写入fileUuid
            _writer.Write(agp.graphs.Length); // 写入graph数量

            for (int i = 0; i < agp.graphs.Length; i++) {
                _writer.Write((ulong)agp.graphs[i].uuid); // 写入graphUuid
                _writer.Write((ulong)agp.graphs[i].name); // 写入graphName
            }

            for (int i = 0; i < agp.graphs.Length; i++) {
                var dryData = AGPParser.ParseAGPToDry(agp.graphs[i]);
                WriteBlock(dryData); // 写入graph
            }

            _writer.Write(agp.resources.Length); // 写入res数量
            for (int i = 0; i < agp.resources.Length; i++) {
                WriteResource(agp.resources[i]); // 写入res
            }

            _writer.Write(agp.timelines.Length); // 写入timeline数量
            for (int i = 0; i < agp.timelines.Length; i++) {
                _writer.Write((ulong)agp.timelines[i].uuid); // 写入timeline uuid

                int eventLength = agp.timelines[i].events.Length;
                _writer.Write(eventLength); // 写入 event 数量
                for (int j = 0; j < eventLength; j++) {
                    _writer.Write(agp.timelines[i].events[j].time); // 写入 event 时间
                    _writer.Write(agp.timelines[i].events[j].endTime); // 写入 event 时间
                    _writer.Write((byte)agp.timelines[i].events[j].state); // 写入 event 时机(on/off/trigger)
                    _writer.Write((uint)agp.timelines[i].events[j].flag); // 写入 event 各种标识
                    _writer.Write((ulong)agp.timelines[i].events[j].parameter.typeUuid); // 写入 event type uuid
                    agp.timelines[i].events[j].parameter.Write(this); // 写入 event 参数
                }
            }

            // Debug.Log("[BufferWriter] agp bin size = " + _stream.Length);
        }

        public void WriteInt32(int v) {
            _writer.Write(v);
        }

        public void WriteUInt64(ulong v) {
            _writer.Write(v);
        }

        public unsafe void WriteStruct<T>(T obj) where T : unmanaged {
            int size = sizeof(T);
            byte[] buffer = new byte[size];
            fixed (byte* bufferPtr = buffer) {
                *(T*)bufferPtr = obj;
            }
            _writer.Write(buffer);
        }

        int WriteBlock(byte[] block) {
            if (block == null)
                throw new ArgumentNullException(nameof(block));

            _writer.Write(block.Length);
            _writer.Write(block);
            return 4 + block.Length;
        }

        int WriteResource(AnimGraphPublishAsset.Resource res) {
            int size = 8;
            _writer.Write((ulong)res.uuid);
            size += WriteString(res.url);
            size += WriteString(res.url2);
            return size;
        }

        int WriteString(string value) {
            if (value == null) {
                _writer.Write(-1); // 写入特殊标记表示字符串为 null
                return 4;
            }

            // 编码字符串为字节数组
            byte[] encodedString = Encoding.UTF8.GetBytes(value);

            // 写入长度和内容
            _writer.Write(encodedString.Length);
            _writer.Write(encodedString);
            return encodedString.Length + 4;
        }

    }


    public class BinaryDataBufferReader : IDisposable {
        private readonly MemoryStream _stream;
        private readonly BinaryReader _reader;

        public BinaryDataBufferReader(byte[] data) {
            _stream = new MemoryStream(data);
            _reader = new BinaryReader(_stream, Encoding.UTF8);
        }

        public void Dispose() {
            _reader?.Dispose();
            _stream?.Dispose();
        }

        public AGDData GetAGD() {
            var agd = new AGDData();
            agd.fileUuid = _reader.ReadUInt64(); // fileUuid
            var graphCount = _reader.ReadInt32(); // graph数量

            agd.graphs = new AGDData.Graph[graphCount];
            // agd.graphUuids = new AUID[graphCount];
            // agd.graphNames = new AUID[graphCount];
            for (int i = 0; i < graphCount; i++) {
                // agd.graphUuids[i] = _reader.ReadUInt64(); // graphUuid
                agd.graphs[i].graphUuid = _reader.ReadUInt64(); // graphUuid
                // agd.graphNames[i] = _reader.ReadUInt64(); // graphName
                agd.graphs[i].graphName = _reader.ReadUInt64(); // graphName
            }

            // agd.graphBytes = new byte[graphCount][];
            for (int i = 0; i < graphCount; i++) {
                // agd.graphBytes[i] = ReadBlock(); // bytes
                agd.graphs[i].bytes = ReadBlock(); // bytes
            }

            var resLength = _reader.ReadInt32(); // res数量
            agd.resources = new AnimGraphPublishAsset.Resource[resLength];
            for (int i = 0; i < resLength; i++) {
                agd.resources[i] = ReadResource();
            }

            int timelineLength = _reader.ReadInt32(); // timeline数量
            agd.timelines = new ReadedTimeline[timelineLength];
            for (int i = 0; i < timelineLength; i++) {
                agd.timelines[i].uuid = _reader.ReadUInt64(); // timeline uuid

                int eventLength = _reader.ReadInt32(); // event 数量
                agd.timelines[i].eventsTemp = new(eventLength);
                agd.timelines[i].alwaysEventsTemp = new(eventLength);
                int j = 0;
                for (; j < eventLength; j++) {
                    ReadedTimelineEvent evt = new();
                    evt.time = _reader.ReadSingle(); // event 时间
                    evt.endTime = _reader.ReadSingle(); // event 时间
                    evt.state = (TimelineEventState)_reader.ReadByte(); // event 时机
                    evt.flag = (TimelineEventFlag)_reader.ReadUInt32(); // event 各种标识
                    evt.typeUuid = (AUID)_reader.ReadUInt64(); // event类型的uuid
                    var parameter = TimelineReader.Read(this); // event 参数
                    evt.parameter = parameter;
                    agd.timelines[i].AddEvent(ref evt);
                }
                agd.timelines[i].FinishAddEvent(j);
            }

            return agd;
        }

        public int ReadInt32() {
            return _reader.ReadInt32();
        }

        public ulong ReadUInt64() {
            return _reader.ReadUInt64();
        }

        public unsafe byte[] ReadStruct(int length) {
            var b = _reader.ReadBytes(length);
            return b;
        }

        byte[] ReadBlock() {
            int length = _reader.ReadInt32();
            return _reader.ReadBytes(length);
        }

        AnimGraphPublishAsset.Resource ReadResource() {
            var res = new AnimGraphPublishAsset.Resource();
            res.uuid = _reader.ReadUInt64();
            res.url = ReadString();
            res.url2 = ReadString();
            return res;
        }

        string ReadString() {
            // 读取字符串长度
            int length = _reader.ReadInt32();
            if (length == -1) return null; // 特殊标记表示字符串为 null

            // 读取字符串内容
            byte[] encodedString = _reader.ReadBytes(length);
            return Encoding.UTF8.GetString(encodedString);
        }
    }

    public struct AGDData {
        public struct Graph {
            public AUID graphUuid;
            public AUID graphName;
            public byte[] bytes;
        }

        public AUID fileUuid;
        public Graph[] graphs;
        // public AUID[] graphUuids;
        // public AUID[] graphNames;
        // public byte[][] graphBytes;
        public AnimGraphPublishAsset.Resource[] resources;
        public ReadedTimeline[] timelines;
    }

    public static class TimelineReader {
        public static byte[] Read(BinaryDataBufferReader reader) {
            int size = reader.ReadInt32();
            byte[] obj;
            if (size != 0) {
                obj = reader.ReadStruct(size);
            } else {
                obj = null;
            }
            return obj;
        }

        /// <summary>
        /// 解析obj的部分
        /// 一般在事件触发的处理里调用，那里才知道T是什么 
        /// </summary>
        public static unsafe T Parse<T>(byte[] obj) where T : unmanaged {
            fixed (byte* ptr = obj) {
                return *(T*)ptr;
            }
        }
    }

    public struct ReadedTimeline {
        public AUID uuid;
        public List<ReadedTimelineEvent> eventsTemp;
        public List<ReadedTimelineEvent> alwaysEventsTemp;
        public ReadedTimelineEvent[] events; // 除always之外的事件
        public ReadedTimelineEvent[] alwaysEvents; // always事件单独放
        public void AddEvent(ref ReadedTimelineEvent evt) {
            // 范围事件需要拆分成2个
            if (evt.state == TimelineEventState.HoldStart) {
                int pairIndex = eventsTemp.Count; // 先让两个事件有相同的pairIndex，用于识别配对关系，排序后替换成彼此的序号
                // start
                evt.pairIndex = pairIndex;
                eventsTemp.Add(evt);
                // end
                var endEvt = new ReadedTimelineEvent() {
                    typeUuid = evt.typeUuid,
                    state = TimelineEventState.HoldEnd,
                    flag = evt.flag,
                    time = evt.endTime,
                    parameter = null,
                    pairIndex = pairIndex,
                };
                eventsTemp.Add(endEvt);
            } else if (evt.state == TimelineEventState.Always) {
                alwaysEventsTemp.Add(evt);
            } else {
                evt.pairIndex = -1;
                eventsTemp.Add(evt);
            }
        }

        public void FinishAddEvent(int loopCount) {
            alwaysEvents = alwaysEventsTemp.ToArray();
            alwaysEventsTemp = null;

            // 用loopCount辅助判断是否含有拆分成2个的事件
            if (loopCount == eventsTemp.Count) {
                events = eventsTemp.ToArray();
                eventsTemp = null;
                return;
            }
            eventsTemp.Sort((l, r) => l.time.CompareTo(r.time));
            var pairCache = new Dictionary<int, int>(eventsTemp.Count - loopCount); // pairIndex, start的index
            for (int i = 0; i < eventsTemp.Count; i++) {
                var evt = eventsTemp[i];
                if (evt.pairIndex != -1) {
                    if (evt.state == TimelineEventState.HoldStart) {
                        pairCache.Add(evt.pairIndex, i);
                    } else if (evt.state == TimelineEventState.HoldEnd) {
                        var otherIndex = pairCache[evt.pairIndex];
                        var otherEvt = eventsTemp[otherIndex];
                        otherEvt.pairIndex = i;
                        evt.pairIndex = otherIndex;
                        eventsTemp[i] = evt;
                        eventsTemp[otherIndex] = otherEvt;
                    }
                }
            }
            events = eventsTemp.ToArray();
            eventsTemp = null;
        }
    }

    /// <summary>
    /// 反序列化后的事件配置信息，是常量
    /// </summary>
    public struct ReadedTimelineEvent {
        public AUID typeUuid;
        public TimelineEventState state; // 事件的触发时机
        public TimelineEventFlag flag; // 事件的可选项，比如“是否确保触发”
        public float time; // 触发时间
        public float endTime; // 对于HoldStart来说是结束的时间，对其它类型无用
        public byte[] parameter; // 编辑器中填写的参数，在事件函数中反序列化后使用，例：TimelineReader.Parse<SetAimingState.Param>(param);
        public int pairIndex; // 非反序列化出的参数，标识范围事件的另一个边界的序号
    }

}
